home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / gopher / Unix / gopher+1.2b4 / gopherd / gopherd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-15  |  52.2 KB  |  2,219 lines

  1. /********************************************************************
  2.  * lindner
  3.  * 3.11
  4.  * 1993/04/15 22:20:08
  5.  * /home/mudhoney/GopherSrc/CVS/gopher+/gopherd/gopherd.c,v
  6.  * Exp
  7.  *
  8.  * Paul Lindner, University of Minnesota CIS.
  9.  *
  10.  * Copyright 1991, 1992 by the Regents of the University of Minnesota
  11.  * see the file "Copyright" in the distribution for conditions of use.
  12.  *********************************************************************
  13.  * MODULE: gopherd.c
  14.  * Routines to implement the gopher server.
  15.  *********************************************************************
  16.  * Revision History:
  17.  * gopherd.c,v
  18.  * Revision 3.11  1993/04/15  22:20:08  lindner
  19.  * CAPFILES mods
  20.  *
  21.  * Revision 3.10  1993/04/15  04:48:07  lindner
  22.  * Debug code from Mitra
  23.  *
  24.  * Revision 3.9  1993/04/10  06:06:11  lindner
  25.  * Admit1 Fixes for combined public/authed server
  26.  *
  27.  * Revision 3.8  1993/04/07  05:54:39  lindner
  28.  * Fixed dreaded .mindex addition problem
  29.  *
  30.  * Revision 3.7  1993/03/26  19:47:50  lindner
  31.  * Hacks to support wais gateway and gplus indexing
  32.  *
  33.  * Revision 3.6  1993/03/25  21:36:30  lindner
  34.  * Mods for directory/recursive etal
  35.  *
  36.  * Revision 3.5  1993/03/24  22:08:59  lindner
  37.  * Removed unused variable
  38.  *
  39.  * Revision 3.4  1993/03/24  20:23:17  lindner
  40.  * Lots of bug fixes, compressed file support, linger fixes, etc.
  41.  *
  42.  * Revision 3.3  1993/03/01  02:22:40  lindner
  43.  * Mucho additions for admit1 stuff..
  44.  *
  45.  * Revision 3.2  1993/02/19  21:21:11  lindner
  46.  * Fixed problems with signals, problems with gethostbyaddr() and
  47.  * inconsisent behavior that depended on the order of files in a directory.
  48.  *
  49.  * Revision 3.1.1.1  1993/02/11  18:02:55  lindner
  50.  * Gopher+1.2beta release
  51.  *
  52.  * Revision 2.8  1993/02/09  22:14:57  lindner
  53.  * many additions for gopher+ stuff..
  54.  *
  55.  * Revision 2.7  1993/01/30  23:57:44  lindner
  56.  * Added extradata handling, language parsing, Fixed extension adding.
  57.  * Fixes for new secure data method.
  58.  * Enhanced link file processing
  59.  * New fcn GDfromSelstr
  60.  *
  61.  * Revision 2.6  1993/01/12  22:53:28  lindner
  62.  * Merged in 1.2.1.6 into mainline release
  63.  *
  64.  * Revision 2.5  1993/01/12  22:48:56  lindner
  65.  * Fixes for mindexd
  66.  *
  67.  * Revision 2.4  1992/12/29  22:13:14  lindner
  68.  * Further refinements to gopher+ stuff.
  69.  * Integrated mindex into the server.
  70.  *
  71.  * Revision 2.3  1992/12/22  21:59:25  lindner
  72.  * Merged in mtm patches to move kernal code to kernutils.c (rev 1.2.1.x)
  73.  *
  74.  * Revision 2.2  1992/12/22  18:56:38  lindner
  75.  * First working gopher+ server with multiple views.  Added Addextension()
  76.  * to get the right filename on the backend.  More mods to GDfromUFS()
  77.  *
  78.  * Revision 2.1  1992/12/21  20:09:46  lindner
  79.  * Added much code and made many changes to move to gopher+
  80.  * Added parse_request, removed a lot of html stuff
  81.  * Added GDfromHTML, etc..  Lots o' stuff..
  82.  *
  83.  * Revision 1.2.1.6  1993/01/09  02:37:29  lindner
  84.  * Added ftp gateway logging
  85.  * Changed gethostbyaddr() to work on UNICOS
  86.  *
  87.  * Revision 1.2.1.5  1993/01/05  21:32:25  lindner
  88.  * Fixed printfile() so that it deals with files with a period on a line
  89.  * all by itself correctly.  Also removed one writestring() call.
  90.  *
  91.  * Revision 1.2.1.4  1993/01/05  21:10:38  lindner
  92.  * Removed setuid() call that broke when using -u and chroot()
  93.  *
  94.  * Revision 1.2.1.3  1992/12/22  21:55:30  lindner
  95.  * fixed typo, int was meant to be double..  Grrrr
  96.  *
  97.  * Revision 1.2.1.2  1992/12/22  21:48:15  lindner
  98.  * Added extern maxload, fixes bug with previous version...
  99.  *
  100.  * Revision 1.2.1.1  1992/12/21  20:51:52  lindner
  101.  * Moved loadrestrict stuff to kernutils.c, also the server
  102.  * can now restrict for load average from standalone mode.
  103.  *
  104.  * Revision 1.2  1992/12/13  06:13:59  lindner
  105.  * Added code to do readline timeouts <mtm>
  106.  *
  107.  * Revision 1.1  1992/12/10  23:13:27  lindner
  108.  * gopher 1.1 release
  109.  *
  110.  *********************************************************************/
  111.  
  112.  
  113. /* Originally derived from an 
  114.  * Example of server using TCP protocol
  115.  * pp 284-5 Stevens UNIX Network Programming
  116.  */
  117.  
  118.  
  119. #include "gopherd.h"
  120. #include "command.h"
  121.  
  122. #undef stat /** Stupid openers thing..**/
  123. #include <sys/stat.h>
  124.  
  125. void LOGGopher();
  126. GopherDirObj *GDfromSelstr();
  127. GopherDirObj *GDfromUFS();
  128.  
  129. static    char*    Gdefusername = NULL;
  130.  
  131. extern char *getdesc();
  132. extern double maxload;
  133. void Process_Side();
  134.  
  135. #include "STAarray.h"
  136. #include "STRstring.h"
  137.  
  138. /* This function is called on a read timeout from the network */
  139.  
  140. #include <setjmp.h>
  141. jmp_buf env;
  142.  
  143. SIGRETTYPE read_timeout(sig)
  144.   int sig;
  145. {
  146.      longjmp(env,1);
  147. }
  148.  
  149.  
  150. /*
  151.  * This routine finds out the hostname of the server machine.
  152.  * It uses a couple of methods to find the fully qualified 
  153.  * Domain name
  154.  */
  155.  
  156. char *
  157. GetDNSname(backupdomain)
  158.   char *backupdomain;
  159. {
  160.      static char DNSname[MAXHOSTNAMELEN];
  161.      struct hostent *hp;
  162.      char *cp;
  163.  
  164.      cp = GDCgetHostname(Config);
  165.      if (*cp != '\0')
  166.       return(cp);
  167.  
  168.      DNSname[0] = '\0';
  169.      /* Work out our fully-qualified name, for later use */
  170.      
  171.      if (gethostname(DNSname, MAXHOSTNAMELEN) != 0) {
  172.       fprintf(stderr, "Cannot determine the name of this host\n");
  173.       exit(-1);
  174.      }
  175.  
  176.      /* Now, use gethostbyname to (hopefully) do a nameserver lookup */
  177.      hp = gethostbyname( DNSname);
  178.  
  179.      /*
  180.       ** If we got something, and the name is longer than hostname, then
  181.       ** assume that it must the the fully-qualified hostname
  182.       */
  183.      if ( hp!=NULL && strlen(hp->h_name) > strlen(DNSname) ) 
  184.       strncpy( DNSname, hp->h_name, MAXHOSTNAMELEN );
  185.      else
  186.       strcat(DNSname, backupdomain);
  187.  
  188.      return(DNSname);
  189. }
  190.  
  191.  
  192. /*
  193.  * Tries to figure out what the currently connected port is.
  194.  * 
  195.  * If it's a socket then it will return the port of the socket, 
  196.  * if it isn't a socket then it returns -1.
  197.  */
  198.  
  199. int 
  200. GetPort(fd)
  201.   int fd;
  202. {
  203.      struct sockaddr_in serv_addr;
  204.  
  205.      int length = sizeof(serv_addr);
  206.      
  207.      /** Try to figure out the port we're running on. **/
  208.      
  209.      if (getsockname(fd, (struct sockaddr *) &serv_addr,&length) == 0)
  210.       return(ntohs(serv_addr.sin_port));
  211.      else
  212.       return(-1);
  213.  
  214. }
  215.  
  216.  
  217. /*
  218.  * This function returns a socket file descriptor bound to the given port
  219.  */
  220.  
  221. int
  222. bind_to_port(port) 
  223.   int port;
  224. {
  225.     struct sockaddr_in serv_addr;
  226.     struct linger linger;
  227.     int reuseaddr = 1;
  228.     int sockfd;
  229.     
  230.     
  231.     if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  232.      err_dump("server: can't open stream socket");
  233.     
  234.     /** Bind our local address so that the client can send to us **/
  235.     
  236.     bzero((char *) &serv_addr, sizeof(serv_addr));
  237.     serv_addr.sin_family         = AF_INET;
  238.     serv_addr.sin_addr.s_addr     = htonl(INADDR_ANY);
  239.     serv_addr.sin_port        = htons(port);
  240.     
  241.     if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr,
  242.            sizeof(reuseaddr)) < 0)
  243.       err_dump("server: can't set REUSEADDR!");
  244.     
  245.     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <0)
  246.      err_dump("server: can't bind local address");
  247.     
  248.     linger.l_onoff = linger.l_linger = 0;
  249.     if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *)&linger,
  250.            sizeof (linger)) < 0)
  251.      err_dump("server: can't turn off linger sockopt");
  252.     
  253.     return(sockfd);
  254. }
  255.  
  256.  
  257. void
  258. main(argc, argv)
  259.   int     argc;
  260.   char     *argv[];
  261. {
  262.      int                childpid;
  263.      int                sockfd, newsockfd;
  264.      int                clilen;
  265.      struct sockaddr_in cli_addr;
  266.      boolean            OptionsRead = FALSE;
  267.  
  268.  
  269.      /*** for getopt processing ***/
  270.      int c;
  271.      extern char *optarg;
  272.      extern int optind;
  273.      int errflag =0;
  274.  
  275.      /* socket options */
  276.      struct linger linger;
  277.  
  278.      pname = argv[0];
  279.      strcpy(Data_Dir, DATA_DIRECTORY);
  280.      err_init();    /* openlog() early - before we chroot() of course */
  281.  
  282.      /*** Check argv[0], see if we're running as gopherls, etc. ***/
  283.  
  284.      RunServer = RunLS = RunIndex = FALSE;
  285.  
  286.      if (strstr(argv[0], "gopherls") != NULL) {
  287.       RunLS = TRUE;
  288.      } else if (strstr(argv[0], "gindexd") != NULL) {
  289.       RunIndex = TRUE;
  290.       dochroot = FALSE;
  291.      } else 
  292.       RunServer = TRUE;  /** Run the server by default **/
  293.  
  294.      Config = GDCnew();  /** Set up the general configuration **/
  295.  
  296.      while ((c = getopt(argc, argv, "mCDIcL:l:o:u:")) != -1)
  297.       switch (c) {
  298.       case 'D':
  299.            DEBUG = TRUE;
  300.            break;
  301.  
  302.       case 'I':
  303.            RunFromInetd = TRUE;
  304.            break;
  305.  
  306.       case 'C':
  307.            Caching = FALSE;
  308.            break;
  309.  
  310.       case 'm':
  311.         if (RunIndex)
  312.             MacIndex = TRUE;
  313.         break;
  314.  
  315.       case 'c':
  316.            dochroot = FALSE;
  317.            if (!RunFromInetd) {
  318.             printf("Not using chroot() - be careful\n");
  319.             if ( getuid() == 0 || geteuid() == 0 )
  320.              printf("You should run without root perms\n");
  321.            }
  322.            break;
  323.  
  324.       case 'L':  /** Load average at which to restrict usage **/
  325.            maxload = atof(optarg);
  326.            break;
  327.  
  328.       case 'l':  /** logfile name **/
  329.            if (*optarg == '/')
  330.             GDCsetLogfile(Config, optarg);
  331.            else {
  332.             char tmpstr[256];
  333.             
  334.             getwd(tmpstr);
  335.             strcat(tmpstr, "/");
  336.             strcat(tmpstr, optarg);
  337.             
  338.             GDCsetLogfile(Config, tmpstr);
  339.            }
  340.            break;
  341.            
  342.       case 'o': /** option file **/
  343.            if (*optarg == '/')
  344.             GDCfromFile(Config, optarg);
  345.            else {
  346.             char tmpstr[256];
  347.             getwd(tmpstr);
  348.             strcat(tmpstr, "/");
  349.             strcat(tmpstr, optarg);
  350.             GDCfromFile(Config, tmpstr);
  351.            }
  352.            OptionsRead = TRUE;
  353.            break;
  354.  
  355.       case 'u':
  356.            {
  357.             struct passwd *pw = getpwnam( optarg );
  358.             if ( !pw ) {
  359.              fprintf(stderr,
  360.                   "Could not find user '%s' in passwd file\n",
  361.                   optarg);
  362.              errflag++;
  363.             } else {
  364.              Gdefusername = optarg;
  365.              if (!RunFromInetd) {
  366.                   printf("Running as user '%s'\n",
  367.                    optarg);
  368.              }
  369.             }
  370.            }
  371.            break;
  372.  
  373.       case '?':
  374.       case 'h':
  375.            errflag++;
  376.            break;
  377.       }
  378.      if (errflag) {
  379.       /* Distribution has Usage for older versions of gopher, doesnt
  380.        * reflect options in newer versions */
  381.       fprintf(stderr, "Usage: %s [-mCDIc] [-u username] [-s securityfile] [-l logfile] [ -L loadavg ] <datadirectory> <port>\n", argv[0]);
  382.       fprintf(stderr, "   -C  turns caching off\n");
  383.       fprintf(stderr, "   -D  enables copious debugging info\n");
  384.       fprintf(stderr, "   -I  enable \"inetd\" mode\n");
  385.       fprintf(stderr, "   -c  disable chroot(), use secure open routines instead\n");
  386.       fprintf(stderr, "   -u  specifies the username for use with -c\n");
  387.       fprintf(stderr, "   -o  override the default options file '%s'\n", CONF_FILE);
  388.       fprintf(stderr, "   -l  specifies the name of a logfile\n");
  389.       fprintf(stderr, "   -L  specifies maximum load to run at\n");
  390.       fprintf(stderr, "   -m  specifies MacIndex, whatever that is\n");
  391.           
  392.       exit(-1);
  393.      }
  394.  
  395. /*     if (uid == -2) 
  396.       uid = getuid();  /** Run as current user... **/
  397.  
  398.      if ( getuid() == 0 && Gdefusername == NULL)
  399.       printf("Warning! You should run the server with the -u option!\n");
  400.  
  401.  
  402.      if (optind < argc) {
  403.       strcpy(Data_Dir, argv[optind]);
  404.       optind++;
  405.       if (DEBUG) 
  406.          printf("main: Setting data to Data Directory is %s\n",Data_Dir);
  407.      } else if (RunLS)
  408.       strcpy(Data_Dir, "/");
  409.  
  410.       if (DEBUG) 
  411.          printf("main: Data Directory is %s\n",Data_Dir);
  412.  
  413.      if (optind < argc) {
  414.       GopherPort = atoi(argv[optind]);
  415.       optind++;
  416.       if (DEBUG) 
  417.          printf("main: Setting port to %d\n",GopherPort);
  418.      }
  419.       if (DEBUG) 
  420.          printf("main: Port is %d\n",GopherPort);
  421.  
  422.      /** Read the options in, if not overridden **/
  423.      if (OptionsRead == FALSE)
  424.       GDCfromFile(Config, CONF_FILE);
  425.  
  426.      /*** Make sure we do a tzset before doing a chroot() ***/
  427.      tzset();
  428.      
  429.  
  430.      if (RunLS) {
  431.       Zehostname =GetDNSname(DOMAIN_NAME);
  432.       Caching = FALSE;
  433.  
  434.       fflush(stdout);
  435.       uchdir(Data_Dir);
  436.  
  437.       listdir(fileno(stdout), "/", FALSE, NULL, NULL);
  438.       exit(0);
  439.      }
  440.  
  441.      if (!RunFromInetd) {
  442.       printf("Gopher Server, Copyright 1991,92 the Regents of the University of Minnesota\n");
  443.       printf("See the file 'Copyright' for conditions of use\n");
  444.       printf("Data directory is %s\n", Data_Dir);
  445.       printf("Port is %d\n", GopherPort);
  446.      }
  447.  
  448.      if (*GDCgetLogfile(Config) != '\0' && !RunFromInetd)
  449.       printf("Logging to File %s\n", GDCgetLogfile(Config));
  450.  
  451.      /*
  452.       * Would like to setuid() here, but have to wait until after the
  453.       * bind() in case we're going to be running on a privileged port.
  454.       */
  455.  
  456.      if (uchdir(Data_Dir)) {
  457.       if (!RunIndex) {
  458.            fprintf(stderr, "Cannot change to data directory!! %s \n",Data_Dir);
  459.            exit(-1);
  460.       }
  461.      }
  462.  
  463.      if (dochroot && getuid() != 0) {
  464.       fprintf(stderr, "Gopherd uses the privileged call chroot().  Please become root.\n");
  465.       exit(-1);
  466.      }
  467.  
  468.      fflush(stderr);
  469.      fflush(stdout);
  470.  
  471.      if (DEBUG == FALSE && RunFromInetd==FALSE)
  472.       daemon_start(0);
  473.  
  474.  
  475.      /*** Hmmm, does this look familiar? :-) ***/
  476.  
  477.  
  478.      err_init();    /* does this look familiar too?? :-) */
  479.  
  480.      /** Ask the system what host we're running on **/
  481.  
  482.      Zehostname = GetDNSname(DOMAIN_NAME);
  483.      if (DEBUG)
  484.       printf("I think your hostname is %s\n", Zehostname);
  485.  
  486.      if (RunFromInetd) {
  487.       /** Ask the system which port we're running on **/
  488.       int newport=0;
  489.       if ((newport =GetPort(0)) !=0)
  490.            GopherPort=newport;
  491.  
  492.       /*** Do the stuff for inetd ***/
  493.  
  494.       while(do_command(fileno(stdout))!=0);    /* process the request */
  495.       exit(0);
  496.      }
  497.  
  498.      /** Open a TCP socket (an internet stream socket **/
  499.      sockfd = bind_to_port(GopherPort);
  500.  
  501.      listen(sockfd, 5);
  502.      
  503.      for ( ; ; ) {
  504.       /*
  505.        * Wait for a connection from a client process.
  506.        * This is an example of a concurrent server.
  507.        */
  508.       
  509.       clilen = sizeof(cli_addr);
  510.       newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr,
  511.                  &clilen);
  512.  
  513.       linger.l_onoff = linger.l_linger = 0;
  514.       if (setsockopt(newsockfd, SOL_SOCKET, SO_LINGER, (char *)&linger,
  515.                  sizeof (linger)) < 0)
  516.            err_dump("server: can't turn off linger sockopt");
  517.  
  518.       if (newsockfd < 0)
  519.            err_dump("server: accept error");
  520.       
  521.       if ( (childpid = fork()) < 0)
  522.            err_dump("server: fork error");
  523.       
  524.       else if (childpid == 0) {    /* Child process */
  525.            close(sockfd);        /* close original socket */
  526.  
  527.            while(do_command(newsockfd)!=0);    /* process the request */
  528.            exit(0);
  529.       }
  530.       /** clean up any zombie children **/
  531.       sig_child();
  532.  
  533.       close(newsockfd);         /* parent process */
  534.      }
  535. }
  536.  
  537.  
  538.  
  539.  
  540. /*
  541.  * This finds the current peer and the time and  jams it into the
  542.  * logfile (if any) and adds the message at the end
  543.  */
  544.  
  545. void
  546. LOGGopher(sockfd, message)
  547.   int sockfd;
  548.   char *message;
  549. {
  550.      static char     host_name[256];
  551.      static char     ipnum[256];
  552.      time_t          Now;
  553.      char            *cp;
  554.                      /* cp + ' ' + host_name + ' : ' + MAXLINE + '\n' + '\0' */
  555.      char            buf[286+MAXLINE];
  556.      struct flock    lock;
  557.    
  558.  
  559.      host_name[0] = '\0';
  560.  
  561.      if (LOGFileDesc != -1) {
  562.       
  563.       if (sockfd > -1) {
  564.            inet_netnames(sockfd,host_name, ipnum);
  565.       }
  566.  
  567.       lock.l_type = F_WRLCK;
  568.       lock.l_whence = SEEK_SET;
  569.           lock.l_start = 0L;
  570.           lock.l_len = 0L;
  571.           fcntl(LOGFileDesc, F_SETLKW, &lock);
  572.  
  573.       time(&Now);         /* Include this in the lock to make sure */
  574.       cp = ctime(&Now);   /*  log entries are chronological */
  575.       ZapCRLF(cp);
  576.  
  577.           /* someone else may have written to the file since we opened it */
  578.           lseek(LOGFileDesc, 0L, SEEK_END);
  579.   
  580.           sprintf(buf, "%s %d %s : %s\n", cp, getpid(), host_name, message);
  581.           write(LOGFileDesc, buf, strlen(buf));
  582.           
  583.           /* unlock the file */
  584.           lock.l_type = F_UNLCK;
  585.           fcntl(LOGFileDesc, F_SETLKW, &lock);
  586.       
  587.       if (DEBUG)
  588.            printf("%s %d %s : %s\n", cp, getpid(), host_name, message);
  589.       
  590.      }
  591. }
  592.  
  593. void
  594. process_mailfile(sockfd, Mailfname)
  595.   int sockfd;
  596.   char *Mailfname;
  597. {
  598.      FILE *Mailfile;
  599.      char Zeline[MAXLINE];
  600.      char outputline[MAXLINE];
  601.      char Title[MAXLINE];
  602.      long Startbyte=0, Endbyte=0, Bytecount=0;
  603.      boolean flagged = 0;
  604.  
  605.      if (DEBUG) fprintf(stderr,"process_mailfile %s\r\n",Mailfname);
  606.  
  607.      Mailfile = rfopen(Mailfname, "r");
  608.  
  609.      if (Mailfile == NULL) {
  610.       Abortoutput(sockfd, "Cannot access file");
  611.       return;
  612.      }
  613.  
  614.      while (fgets(Zeline, MAXLINE, Mailfile) != NULL) {
  615.       if (strncmp(Zeline, "Subject: ", 9)==0 && (!flagged)) {
  616.            flagged =1;
  617.            strcpy(Title, Zeline + 9);
  618.            ZapCRLF(Title);
  619.            if (DEBUG)
  620.             fprintf(stderr, "Found title %s\n", Title);
  621.       }
  622.       
  623.       if (is_mail_from_line(Zeline)==0) {
  624.            Endbyte = Bytecount;
  625.            flagged =0;
  626.  
  627.            if (Endbyte != 0) {
  628.             sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n", 
  629.                 Title, Startbyte, Bytecount, Mailfname,
  630.                 Zehostname, GopherPort);
  631.             if (writestring(sockfd, outputline) < 0)
  632.              LOGGopher(sockfd, "Client went away"), exit(-1);
  633.             Startbyte=Bytecount;
  634.             *Title = '\0';
  635.            }
  636.       }
  637.  
  638.       Bytecount += strlen(Zeline);
  639.      }
  640.  
  641.      if (*Title != '\0') {
  642.       sprintf(outputline, "0%s\tR%d-%d-%s\t%s\t%d\r\n", 
  643.           Title, Startbyte, Bytecount, Mailfname, 
  644.           Zehostname, GopherPort);
  645.       if (writestring(sockfd, outputline)<0)
  646.            LOGGopher(sockfd, "Client went away"),exit(-1);
  647.      }      
  648.  
  649. }
  650.  
  651.  
  652.  
  653. boolean
  654. Can_Read(sockfd)
  655.   int sockfd;
  656. {
  657.      int                length;
  658.      char               host_name[256];
  659.      char               ip[256];
  660.      char               *cp;
  661.  
  662.      inet_netnames(sockfd, host_name, ip);
  663.  
  664.      return(GDCCanRead(Config, host_name, ip));
  665. }
  666.  
  667. boolean
  668. Can_Browse(sockfd)
  669.   int sockfd;
  670. {
  671.      int                length;
  672.      char               host_name[256];
  673.      char               ip[256];
  674.      char               *cp;
  675.  
  676.      inet_netnames(sockfd, host_name, ip);
  677.  
  678.      return(GDCCanBrowse(Config, host_name, ip));
  679. }
  680.  
  681. boolean
  682. Can_Search(sockfd)
  683.   int sockfd;
  684. {
  685.      int                length;
  686.      char               host_name[256];
  687.      char               ip[256];
  688.      char               *cp;
  689.      char               tmpstr[256];
  690.  
  691.      inet_netnames(sockfd, host_name, ip);
  692.  
  693.      return(GDCCanSearch(Config, host_name, ip));
  694. }
  695.  
  696.  
  697.  
  698. char *
  699. AddExtension(filename, view)
  700.   char *filename;
  701.   char *view;
  702. {
  703.      boolean status = TRUE;
  704.      Extobj *ext;
  705.      struct stat statbuf;
  706.      static char tmpfilename[256];
  707.  
  708.      if (*filename == '\0')
  709.       return(filename);
  710.  
  711.      ext = EXnew();
  712.  
  713.      strcpy(tmpfilename, filename);
  714.  
  715.      status = EXAviewSearch(Config->Extensions, ext, view);
  716.      if (status == TRUE)
  717.       strcat(tmpfilename, EXgetExt(ext));
  718.      
  719.      if (rstat(tmpfilename+1, &statbuf)) {
  720.       /** Couldn't find the file, return original filename **/
  721.       EXdestroy(ext);
  722.       return(filename);
  723.      } else 
  724.       status = FALSE;
  725.      
  726.      EXdestroy(ext);
  727.      return(tmpfilename);
  728. }
  729.  
  730.  
  731.  
  732.  
  733. #define DODEBUG(loc) if (DEBUG) { sprintf(debugout,"do_command:%s:Selstr=%s; view=%s;\r\n",loc,Selstr,view); writestring(sockfd,debugout); }
  734. int
  735. do_command(sockfd)
  736.   int sockfd;
  737. {
  738.      char inputline[MAXLINE];
  739.      int     length;        /* Length of the command line */
  740.      char    logline[MAXLINE];
  741.      char    *view     = NULL;
  742.      char    *Selstr   = NULL;
  743.      CMDobj  *cmd;
  744.      char    *filter   = NULL;
  745.      TixObj  *tix      = NULL;
  746.     char    debugout[255];
  747.  
  748.      cmd = CMDnew();
  749.  
  750.      /*** Reopen the log file ***/
  751.  
  752.      if (*GDCgetLogfile(Config) != '\0') {
  753.       LOGFileDesc = uopen(GDCgetLogfile(Config), O_WRONLY | O_APPEND |O_CREAT, 0644);
  754.       
  755.       if (LOGFileDesc == -1) {
  756.            printf("Can't open the logfile: %s\n", GDCgetLogfile(Config));
  757.            exit(-1);
  758.       }
  759.      }
  760.  
  761.      DODEBUG("Checking Load")
  762.      if(LoadTooHigh()) {
  763.       Abortoutput(sockfd, "System is too busy right now. Please try again later.");
  764.       exit(-1);
  765.      }
  766.  
  767.  
  768.      (void) signal(SIGALRM,read_timeout);
  769.      (void) alarm(READTIMEOUT);
  770.  
  771.      if(setjmp(env)) {
  772.       LOGGopher(sockfd,"readline: Timed out!");
  773.       Abortoutput(sockfd,"readline: Timed out!");
  774.       exit(-1);
  775.      }
  776.  
  777.      CMDfromNet(cmd, sockfd);
  778.      ASKfile = CMDgetAskfile(cmd);
  779.  
  780.      if (RunIndex) {
  781.       /*** Run like the old gindexd thing. ***/
  782.       
  783.       uchdir("/");
  784.       strcpy(Data_Dir, "/");
  785.  
  786.       if (*CMDgetSelstr(cmd) == '\t')
  787.            Do_IndexTrans(sockfd, Data_Dir, CMDgetSearch(cmd)+1);
  788.       else
  789.            Do_IndexTrans(sockfd, Data_Dir, CMDgetSearch(cmd));
  790.  
  791.       Do_IndexTrans(sockfd, Data_Dir, CMDgetSearch(cmd));
  792.       return(0);
  793.      }
  794.  
  795.      
  796. #ifdef UMNDES
  797.      if (CMDgetTicket(cmd) != NULL) {
  798.       /*** Test the ticket, and set the appropriate user ***/
  799.       tix=ValidTicket(sockfd, cmd);
  800.  
  801.       if (tix == NULL)
  802.            return(0);
  803.       
  804.       if (Setuid_username(TIXgetUser(tix))==FALSE)
  805.            printf("Failed to set username to %s\n", TIXgetUser(tix));
  806.       if (DEBUG)
  807.            printf("We're now running as uid %d\n", geteuid());
  808.      } else
  809.       /*** No ticket given, default to the defuser ***/
  810.       if (Gdefusername && Setuid_username(Gdefusername) == FALSE) {
  811.            if (DEBUG) 
  812.             printf("Couldn't change uid to %s\n",Gdefusername);
  813.            Abortoutput(sockfd, "Can't set UID!"), exit(-1);
  814.       }
  815. #else
  816.  
  817.  
  818.      if (Gdefusername && Setuid_username(Gdefusername)== FALSE)
  819.       Abortoutput(sockfd, "Can't set UID!"), exit(-1);
  820. #endif
  821.  
  822.      /** Change our root directory **/
  823.      if ( dochroot ) {
  824.       /** Change back to root for a bit **/
  825.       int tempuid = geteuid();
  826.       
  827.       seteuid(0);
  828.  
  829.       if (chroot(Data_Dir))
  830.            Abortoutput(sockfd, "Data_Dir dissappeared!"), exit(-1);
  831.       
  832.       seteuid(tempuid);
  833.  
  834.       uchdir("/");    /* needed after chroot */
  835.      }
  836.  
  837.  
  838.      /** Extract the view if it exists **/
  839.      if (CMDgetCommand(cmd) != NULL) {
  840.       char *command = CMDgetCommand(cmd);
  841.       if (*command == '+' && strlen(command)>1)
  842.            view = command+1;
  843.       else if (*command == '!') {
  844.            item_info(CMDgetSelstr(cmd), sockfd);
  845.            if (*(command+1) != '\0')
  846.             filter = command + 1;
  847.            return(0);
  848.       }
  849.       else if (*command == '$') {
  850.            if (*(command+1) != '\0')
  851.             filter = command + 1;
  852.            view = "Directory+";
  853.            *command = '+';
  854.       }
  855.       else
  856.            ; /*** Error ***/
  857.      }
  858.      
  859.      if ((strncmp(CMDgetSelstr(cmd), "ftp:",4)==0) ||
  860.      (strncmp(CMDgetSelstr(cmd), "waisdocid:",10)==0))
  861.       view = "Text";
  862.  
  863.      /*** Try to find a view if not supplied ***/
  864.      
  865.      if (view == NULL) {
  866.       GopherDirObj *gd;
  867.       int num,i;
  868.  
  869.  
  870.       /** Get gopher directory containing item in question **/
  871.       gd = GDfromSelstr(CMDgetSelstr(cmd), sockfd);
  872.  
  873.       if (gd != NULL) {
  874.            num = GDSearch(gd, CMDgetSelstr(cmd));
  875.            if (num >=0) {
  876.             GopherObj *gs;
  877.            
  878.             gs= GDgetEntry(gd, num);
  879.  
  880.             /**  If only one view, take it **/
  881.             if (GSgetNumViews(gs) == 1)
  882.              view = VIgetViewnLang(GSgetView(gs, 0),(char*)malloc(128));
  883.             else {
  884.              /*** Hmmm, let's choose one.. ***/
  885.              for (i=0; i<GSgetNumViews(gs); i++) {
  886.                   char *tmpview;
  887.  
  888.                   tmpview = VIgetType(GSgetView(gs,i));
  889.                   if (GSgetType(gs) == '0') {
  890.                    if (strcmp(tmpview, "Text")==0) {
  891.                     view = VIgetViewnLang(GSgetView(gs, i),(char*)malloc(128));
  892.                     break;
  893.                    }
  894.                   }
  895.                   if (GSgetType(gs) == 'I') {
  896.                    if (strcmp(tmpview, "image/gif")==0) {
  897.                     view = VIgetViewnLang(GSgetView(gs, i),(char*)malloc(128));
  898.                     break;
  899.                    }
  900.                   }
  901.  
  902.              }
  903.              if (view == NULL)
  904.                   /** Give up, take the first view... **/
  905.                   view = VIgetViewnLang(GSgetView(gs,0), (char*)malloc(128));
  906.             }
  907.             /** We should have a view by now **/
  908.            }
  909.       }
  910.      }
  911.  
  912.  
  913.      /** Decide whether to add an extension of not .. **/
  914.      if (view != NULL )
  915.       Selstr = AddExtension(CMDgetSelstr(cmd), view);
  916.      else
  917.       Selstr = CMDgetSelstr(cmd);
  918.  
  919.  
  920.      /*** With the funky new capability system we can just check the
  921.           first letter(s), end decide what the object refers to. ***/
  922.  
  923.      switch (*Selstr) {
  924.      case '\0':
  925.      case '\t':
  926.  
  927.       /*** The null capability, so it's not a file, probably wants
  928.            to talk to a directory server ***/
  929.  
  930.       /*** we'll just do a "list" of the root directory, with no user
  931.            capability.  ***/
  932.  
  933.  
  934.       listdir(sockfd, "/", CMDisGplus(cmd), view, filter);
  935.       LOGGopher(sockfd, "Root Connection");
  936.       break;
  937.  
  938.      case 'h':
  939.       /*** A raw html file ***/
  940.       /*** Turn off html'ing and just dump the file ***/
  941.       UsingHTML = FALSE;
  942.  
  943.      case '0':
  944.      case '9':
  945.      case 's':
  946.      case 'I':
  947.      case 'g':
  948.       /*** It's some kind of file ***/
  949.  
  950.       /*** Is it binary??  ***/
  951.       if (view == NULL) 
  952.            printfile(sockfd, Selstr+1, 0, -1, CMDisGplus(cmd));
  953.  
  954.  
  955.       if (GSisText(NULL, view))
  956.            printfile(sockfd, Selstr+1, 0, -1, CMDisGplus(cmd));
  957.       else
  958.            echosound(sockfd, Selstr+1, CMDisGplus(cmd));
  959.            
  960.       /*** Log it ***/
  961.       strcpy(logline, "retrieved file ");
  962.       strcat(logline, Selstr+1);
  963.       LOGGopher(sockfd, logline);
  964.       break;
  965.  
  966.  
  967.      case '1':
  968.       /*** It's a directory capability ***/
  969.       listdir(sockfd, Selstr+1, CMDisGplus(cmd), view, filter);
  970.  
  971.       /** Log it **/
  972.       strcpy(logline, "retrieved directory ");
  973.       strcat(logline, Selstr+1);
  974.       LOGGopher(sockfd, logline);
  975.  
  976.       break;
  977.  
  978.      case '7':
  979.       /*** It's an index capability ***/
  980.       if (Can_Search(sockfd) == FALSE) {
  981.            char tmpstr[256];
  982.  
  983.            Abortoutput(sockfd, GDCgetBummerMsg(Config));
  984.             
  985.            sprintf(tmpstr, "Denied access for %s", Selstr+1);
  986.            LOGGopher(sockfd, tmpstr);
  987.            break;
  988.       }
  989.  
  990.       Do_IndexTrans(sockfd, Selstr+1, cmd);
  991.  
  992.       break;
  993.  
  994.  
  995.      case 'm':
  996.       if (strncmp(Selstr, "mindex:", 7)==0) {
  997.            /*** First test for multiple indexes ***/
  998.                  if (Can_Search(sockfd) == FALSE) {
  999.                char tmpstr[256];
  1000.                
  1001.                Abortoutput(sockfd, GDCgetBummerMsg(Config));
  1002.                
  1003.                sprintf(tmpstr, "Denied access for %s", Selstr+1);
  1004.                LOGGopher(sockfd, tmpstr);
  1005.                break;
  1006.           }
  1007.           do_mindexd(sockfd, Selstr+7, CMDgetSearch(cmd));
  1008.           break;
  1009.          }
  1010.  
  1011.  
  1012.       /*** This is an internal identifier ***/
  1013.       /*** The m paired with an Objtype of 1 makes a mail spool file
  1014.         into a directory.
  1015.         ***/
  1016.       if (Can_Browse(sockfd) == FALSE) {
  1017.            char tmpstr[256];
  1018.            Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  1019.            sprintf(tmpstr, "Denied access for %s", Selstr+1);
  1020.            LOGGopher(sockfd, tmpstr);
  1021.            break;
  1022.       }
  1023.  
  1024.       process_mailfile(sockfd, Selstr + 1);
  1025.       writestring(sockfd, ".\r\n");
  1026.  
  1027.       /** Log it **/
  1028.       strcpy(logline, "retrieved maildir ");
  1029.       strcat(logline, Selstr+1);
  1030.       LOGGopher(sockfd, logline);
  1031.  
  1032.       break;
  1033.  
  1034.      case 'R':
  1035.       /*** This is an internal identifier ***/
  1036.       /*** The R defines a range  ****/
  1037.       /*** The format is R<startbyte>-<endbyte>-<filename> **/
  1038.      {
  1039.       int startbyte, endbyte;
  1040.       char *cp, *oldcp;
  1041.  
  1042.       cp = strchr(Selstr+1, '-');
  1043.       
  1044.       if (cp == NULL) {
  1045.            Abortoutput(sockfd, "Range specifier error");
  1046.            break;
  1047.       }
  1048.       
  1049.       *cp = '\0';
  1050.       startbyte = atoi(Selstr+1);
  1051.       oldcp = cp+1;
  1052.  
  1053.       cp = strchr(oldcp, '-');
  1054.       
  1055.       if (cp == NULL) {
  1056.            Abortoutput(sockfd, "Range specifier error");
  1057.            exit(-1);
  1058.       }
  1059.  
  1060.       *cp = '\0';
  1061.       endbyte = atoi(oldcp);
  1062.       oldcp = cp + 1;
  1063.       if (DEBUG)
  1064.            fprintf(stderr, "Start: %d, End: %d  File: %s\n", startbyte, endbyte, oldcp);
  1065.  
  1066.       printfile(sockfd, oldcp, startbyte, endbyte, CMDisGplus(cmd));
  1067.  
  1068.       /*** Log it ***/
  1069.       sprintf(logline, "retrieved range %d - %d of file %s", startbyte, endbyte, oldcp);
  1070.       LOGGopher(sockfd, logline);
  1071.       break;
  1072.      }
  1073.  
  1074.      case 'f':
  1075.       if (Can_Browse(sockfd) == FALSE) {
  1076.            char tmpstr[256];
  1077.            Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  1078.            sprintf(tmpstr, "Denied access for %s", Selstr);
  1079.            LOGGopher(sockfd, tmpstr);
  1080.            break;
  1081.       }
  1082.  
  1083.       if (strncmp(Selstr, "ftp:",4)==0){
  1084.            sprintf(logline, "retrieved %s", Selstr);
  1085.            LOGGopher(sockfd, logline);
  1086.  
  1087.            SendFtpQuery(sockfd, Selstr+4);
  1088.            TranslateResults(sockfd);
  1089.            break;
  1090.       }
  1091.       break;
  1092.  
  1093.  
  1094.      case 'e':
  1095.       if (Can_Browse(sockfd) == FALSE) {
  1096.            char tmpstr[256];
  1097.            Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  1098.            sprintf(tmpstr, "Denied access for %s", Selstr);
  1099.            LOGGopher(sockfd, tmpstr);
  1100.            break;
  1101.       }
  1102.  
  1103.       if (strncmp(Selstr, "exec:", 5)==0) {
  1104.            /* args are between colons */
  1105.            char *args, *command;
  1106.            
  1107.            command = strrchr(Selstr + 5, ':');
  1108.            if (command == NULL)
  1109.             break;
  1110.  
  1111.            if (*(Selstr+5) == ':' && *(Selstr+6) == ':')
  1112.             args = NULL;
  1113.            else
  1114.             args = Selstr+5;
  1115.  
  1116.            *command = '\0';
  1117.            command++;
  1118.            
  1119.            EXECargs = args;
  1120.  
  1121.            printfile(sockfd, command, 0, -1, CMDisGplus(cmd));
  1122.       }
  1123.       break;
  1124.  
  1125.      case 'w':
  1126.      {
  1127.       if (strncmp(Selstr, "waissrc:", 8) == 0) {
  1128.            char waisfname[512];  /*** Ick this is gross ***/
  1129.  
  1130.            if (Can_Search(sockfd) == FALSE) {
  1131.             char tmpstr[256];
  1132.             Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  1133.             sprintf(tmpstr, "Denied access for %s", Selstr);
  1134.             LOGGopher(sockfd, tmpstr);
  1135.             break;
  1136.            }
  1137.            strcpy(waisfname, Selstr+8);
  1138.            strcat(waisfname, ".src");
  1139.            SearchRemoteWAIS(sockfd, waisfname, cmd);
  1140.            break;
  1141.       }
  1142.       else if (strncmp(Selstr, "waisdocid:", 10) == 0) {
  1143.            if (Can_Browse(sockfd) == FALSE) {
  1144.             char tmpstr[256];
  1145.             Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  1146.             sprintf(tmpstr, "Denied access for %s", Selstr);
  1147.             LOGGopher(sockfd, tmpstr);
  1148.             break;
  1149.            }
  1150.            Fetchdocid(sockfd, Selstr+10);
  1151.            break;
  1152.       }
  1153.      }
  1154.  
  1155.  
  1156.      default:
  1157.       /*** Hmmm, must be an old link... Let's see if it exists ***/
  1158.  
  1159.       switch (isadir(Selstr)) {
  1160.       case -1:
  1161.            /* no such file */
  1162.            sprintf(logline, "'%s' does not exist", Selstr);
  1163.            LOGGopher(sockfd, logline);
  1164.            Abortoutput(sockfd, logline);
  1165.            break;
  1166.  
  1167.       case 0:
  1168.            /* it's a file */
  1169.            printfile(sockfd, Selstr, 0, -1, CMDisGplus(cmd));
  1170.            
  1171.            /* Log it... */
  1172.            strcpy(logline, "retrieved file ");
  1173.            strcat(logline, Selstr);
  1174.            LOGGopher(sockfd, logline);
  1175.  
  1176.            break;
  1177.  
  1178.       case 1:
  1179.            /* it's a directory */
  1180.            listdir(sockfd, Selstr, CMDisGplus(cmd), view, filter);
  1181.  
  1182.            /* Log it */
  1183.            strcpy(logline, "retrieved directory ");
  1184.            strcat(logline, inputline);
  1185.            LOGGopher(sockfd, logline);
  1186.  
  1187.            break;
  1188.       }
  1189.      }
  1190.  
  1191.      return(0);
  1192. }
  1193.  
  1194.  
  1195. /*
  1196.  * This function tries to find out what type of file a pathname is.
  1197.  */
  1198.  
  1199. void
  1200. Getfiletypes(newpath, filename, gs)
  1201.   char *newpath;
  1202.   char *filename;
  1203.   GopherObj *gs;
  1204. {
  1205.      int Zefilefd;
  1206.      static char Zebuf[256];
  1207.      char *cp;
  1208.      static char Selstr[512];
  1209.  
  1210.      
  1211.      switch (isadir(filename)) {
  1212.      case -1:
  1213.       GSsetType(gs,'3');
  1214.       return;
  1215.  
  1216.      case 1:
  1217.       GSsetType(gs,A_DIRECTORY);
  1218.       *Selstr = '1';
  1219.       strcpy(Selstr +1, newpath);
  1220.       GSsetPath(gs, Selstr);
  1221.       return;
  1222.      default:
  1223.  
  1224.       /*** The default is a generic text file ***/
  1225.       GSsetType(gs, A_FILE);
  1226.  
  1227.       *Selstr = '0';
  1228.       strcpy(Selstr + 1, newpath);
  1229.  
  1230.       /*** Test and see if the thing exists... and is readable ***/
  1231.       
  1232.       if ((Zefilefd = ropen(filename, O_RDONLY)) < 0) {
  1233.            GSsetType(gs, '3');
  1234.            return;
  1235.       }
  1236.       
  1237.       if (read(Zefilefd, Zebuf, sizeof(Zebuf)) <0) {
  1238.            GSsetType(gs, '3');
  1239.            return;
  1240.       }
  1241.       close(Zefilefd);
  1242.       
  1243.       /*** Check the first few bytes for sound data ***/
  1244.       
  1245.       cp = Zebuf;
  1246.  
  1247.       if (strncmp(cp, ".snd", 4)==0) {
  1248.            GSsetType(gs, A_SOUND);
  1249.            *Selstr = 's';
  1250.            strcpy(Selstr+1, newpath);
  1251.       }
  1252.  
  1253.       /*** Check and see if it's mailbox data ***/
  1254.       
  1255.       if (is_mail_from_line(Zebuf)==0) {
  1256.            GSsetType(gs, A_DIRECTORY);
  1257.            *Selstr = 'm';
  1258.            strcpy(Selstr+1, newpath);
  1259.            GSsetGplus(gs, FALSE);  /** Not yet.. **/
  1260.       }
  1261.       
  1262.  
  1263.       /*** Check for uuencoding data ***/
  1264.  
  1265.       if (strncmp(cp,"begin",6) == 0)  {
  1266.            GSsetType(gs, '6');
  1267.            *Selstr = '6';
  1268.            strcpy(Selstr+1, newpath);
  1269.       }
  1270.       
  1271.       /*** Check for GIF magic code ***/
  1272.       
  1273.       if (strncmp(cp, "GIF", 3) == 0) {
  1274.            GSsetType(gs, 'I');
  1275.             *Selstr = '9';
  1276.             strcpy(Selstr + 1, newpath);
  1277.        }
  1278.  
  1279.       GSsetPath(gs, Selstr);
  1280.  
  1281.       /*** Okay, now let's check for the stuff from gopherd.conf files ***/
  1282.       
  1283.      }
  1284. }
  1285.  
  1286. /*
  1287.  * Add a default view if none exists..
  1288.  */
  1289.  
  1290. void
  1291. AddDefaultView(gs, size, lang)
  1292.   GopherObj *gs;
  1293.   int size;
  1294.   char *lang;
  1295. {
  1296.  
  1297.      if (lang == NULL)
  1298.       lang = GDCgetLang(Config);
  1299.      
  1300.      switch (GSgetType(gs)) {
  1301.      case A_FILE:
  1302.       GSaddView(gs, "Text", lang, size);
  1303.       break;
  1304.      case A_DIRECTORY:
  1305.       GSaddView(gs, "Directory", lang, size);
  1306.       GSaddView(gs, "Directory+", lang, size);
  1307.       break;
  1308.      case A_MACHEX:
  1309.       GSaddView(gs, "application/binhex", lang, size);
  1310.       break;
  1311.      case A_PCBIN:
  1312.       GSaddView(gs, "application/dos", lang, size);
  1313.       break;
  1314.      case A_CSO:
  1315.       GSaddView(gs, "application/qi", lang, 0);
  1316.       break;
  1317.      case A_INDEX:
  1318.       GSaddView(gs, "Directory", lang, size);
  1319.       GSaddView(gs, "Directory+", lang, size);
  1320.       break;
  1321.      case A_TELNET:
  1322.       GSaddView(gs, "application/telnet", lang, 0);
  1323.       break;
  1324.      case A_SOUND:
  1325.       GSaddView(gs, "sound/basic", lang, size);
  1326.       break;
  1327.      case A_UNIXBIN:
  1328.       GSaddView(gs, "application/octet-stream", lang, size);
  1329.       break;
  1330.      case A_GIF:
  1331.       GSaddView(gs, "image/gif", lang, size);
  1332.       break;    
  1333.      case A_HTML:
  1334.       GSaddView(gs, "application/HTML", lang, size);
  1335.       break;
  1336.      case A_TN3270:
  1337.       GSaddView(gs, "application/tn3270", lang, 0);
  1338.       break;
  1339.      case A_MIME:
  1340.       GSaddView(gs, "multipart/mixed", lang, size);
  1341.       break;
  1342.      case A_IMAGE:
  1343.       GSaddView(gs, "image", lang, size);
  1344.       break;
  1345.      }
  1346. }
  1347.  
  1348. /*
  1349.  * Add a DL description if it's there ...
  1350.  */
  1351.  
  1352. GStitlefromDL(gs, filename)
  1353.   GopherObj *gs;
  1354.   char *filename;
  1355. {
  1356. #ifdef DL
  1357.      char               dlpath[2];    /*** for DL**/
  1358.      char               *dlout;
  1359.  
  1360.      /* Process a "dl" description if there is one! */
  1361.      
  1362.      dlpath[0] = '.';
  1363.      dlpath[1] = '\0';
  1364.      dlout = getdesc(NULL,dlpath,filename,0);
  1365.      
  1366.      if (DEBUG)
  1367.       printf("dl: %s %s %s\n", dlpath, filename, dlout);
  1368.      if (dlout != NULL) {
  1369.       GSsetTitle(gs, dlout);
  1370.      }
  1371. #endif
  1372.      ;
  1373. }
  1374.  
  1375.  
  1376. /*
  1377.  * Load up a gopher directory from the file system 
  1378.  */
  1379.  
  1380. GopherDirObj *
  1381. GDfromUFS(pathname, sockfd, isGplus)
  1382.   char *pathname;
  1383.   int sockfd;
  1384.   boolean isGplus;
  1385. {
  1386.      DIR                *ZeDir;
  1387.      char               filename[256];
  1388.      static char        newpath[512];
  1389.      static GopherObj   *Gopherstow = NULL;
  1390.      static Extobj      *ext = NULL;
  1391.      GopherObj          *gs;
  1392.      struct dirent      *dp;
  1393.      GopherDirObj       *gd;
  1394.      struct stat        statbuf;
  1395.      boolean            AddItem = TRUE;
  1396.      char *Prefix, *View, Gtype, *TheExt;
  1397.      static char        Pathp[512];
  1398.      StrArray           *Linkfiles;
  1399.      int                i, cachefd;
  1400.  
  1401.      Linkfiles = STAnew(10);
  1402.  
  1403.      /*** Make our gopherobj ****/
  1404.      if (Gopherstow == NULL)
  1405.       Gopherstow = GSnew();
  1406.  
  1407.      gs = Gopherstow;
  1408.      if (ext == NULL)
  1409.       ext = EXnew();
  1410.  
  1411.      if (isGplus && GSgplusInited(gs) == FALSE)
  1412.       GSplusnew(gs);
  1413.  
  1414.      gd = GDnew(32);
  1415.  
  1416.      if (rchdir(pathname)<0) {
  1417.       perror("SOL dude");
  1418.       exit(-1);
  1419.      }
  1420.      
  1421.  
  1422.      if (Caching && Cachetimedout(".cache+", CACHE_TIME, ".")) {
  1423.       if ((cachefd = ropen(".cache+", O_RDONLY)) >0) {
  1424.            GDplusfromNet(gd, cachefd, NULL);
  1425.            return(gd);
  1426.       }
  1427.      }
  1428.  
  1429.      /* open "." since we just moved there - makes it work when not
  1430.     chroot()ing and using relative paths */
  1431.      if ((ZeDir = uopendir(".")) == NULL) {
  1432.       char tmpstr[256];
  1433.       getwd(tmpstr);
  1434.       printf("Current Dir is %s\n", tmpstr);
  1435.       fflush(stdout);
  1436.       perror("SOL dude");
  1437.       sprintf(tmpstr, "Cannot access directory '%s'", pathname);
  1438.       Abortoutput(sockfd, tmpstr);
  1439.       return(NULL);
  1440.      }
  1441.  
  1442.      for (dp = readdir(ZeDir); dp != NULL; dp = readdir(ZeDir)) {
  1443. #ifdef CAPFILES
  1444.       char capfile[MAXPATHLEN];
  1445.       int SideFile;
  1446.  
  1447.       strcpy(capfile,".cap/");
  1448.       strcat(capfile, dp->d_name);
  1449. #endif
  1450.  
  1451.           strcpy(newpath, pathname);
  1452.       strcpy(filename, dp->d_name);
  1453.           if (newpath[strlen(newpath)-1] != '/')
  1454.                strcat(newpath, "/");
  1455.           strcat(newpath, dp->d_name);
  1456.  
  1457.       /* Strip any .Z from newpath before process them 
  1458.          filename needs to remain as is for type checking */
  1459.       if (strcmp(dp->d_name+strlen(dp->d_name)-2,".Z") == 0) {
  1460.         newpath[strlen(newpath)-2] = '\0';
  1461.       }
  1462.       AddItem = TRUE;
  1463.       gs = Gopherstow;
  1464.  
  1465.       if (GDCignore(Config,filename))
  1466.            continue;
  1467.       else if (filename[0] == '.' && 
  1468.            strncmp(filename, ".cache",6) != 0 &&
  1469.            isadir(filename)==0) {
  1470.            
  1471.            String *temp;
  1472.            
  1473.            /*** This is a link file, process it after other files ***/
  1474.            
  1475.            temp = STRnew();
  1476.            STRset(temp, filename);
  1477.            
  1478.            STApush(Linkfiles, temp);
  1479.            STRdestroy(temp);
  1480.            continue;
  1481.       } else if (filename[0] == '.') {
  1482.            continue;
  1483.       }
  1484.       
  1485.       ustat(filename, &statbuf);
  1486.       
  1487.       gs = Gopherstow;
  1488.       GSinit(gs);
  1489.       GSsetHost(gs, Zehostname);
  1490.       GSsetPort(gs, GopherPort);
  1491.       GSsetGplus(gs, TRUE);
  1492.       
  1493.       Getfiletypes(newpath, filename, gs);
  1494.  
  1495.       if (GSgetType(gs) == '3')
  1496.            continue;
  1497.       
  1498.       
  1499.       /* If compressed then strip .Z before check for extensions */
  1500.       if (strcmp(filename + strlen(filename) -2, ".Z") ==0 &&
  1501.            strcmp(filename + strlen(filename) -6, ".tar.Z") != 0)
  1502.             filename[strlen(filename) - 2] = '\0';
  1503.  
  1504.       /*** Add views, prefixes et al.. ***/
  1505.       if (GDCBlockExtension(Config, filename, ext)) {
  1506.            char tmpstr[256];
  1507.            int num;
  1508.  
  1509.            /** Strip off the extension from the path **/
  1510.            *tmpstr = ' ';
  1511.            strcpy(tmpstr+1, newpath);
  1512.            tmpstr[1+strlen(newpath)-strlen(EXgetExt(ext))]= '\0';
  1513.            GSsetPath(gs, tmpstr);
  1514.  
  1515.            /*** Strip extension off of title ***/
  1516.            filename[strlen(filename)-strlen(EXgetExt(ext))]= '\0';
  1517.            
  1518.            num = GDSearch(gd, GSgetPath(gs));
  1519.            if (num != -1) {
  1520.             gs = GDgetEntry(gd, num);
  1521.             AddItem = FALSE;
  1522.            } 
  1523.            
  1524.            if (strcasecmp(EXgetBlockname(ext), "ASK") == 0) {
  1525.             GSsetAsk(gs, TRUE);
  1526.            }
  1527.            
  1528.            if (isGplus) {
  1529.             GSaddBlock(gs,EXgetBlockname(ext), fixfile(newpath));
  1530.            }
  1531.            if (AddItem == TRUE)
  1532.             GSsetType(gs, '\0');
  1533.       }
  1534.  
  1535.       else if (GDCViewExtension(Config, filename, &ext)) {
  1536.            char *cp, *Prefix;
  1537.            int num;
  1538.            
  1539.            Prefix = EXgetPrefix(ext);
  1540.  
  1541.            strcpy(Pathp, Prefix);
  1542.            strcpy(Pathp+strlen(Prefix), newpath);
  1543.            
  1544.            /*** Strip extension off of pathname***/
  1545.            Pathp[strlen(Prefix)+strlen(newpath)-strlen(EXgetExt(ext))]= '\0';
  1546.            GSsetPath(gs, Pathp);
  1547.            GSsetType(gs, EXgetObjtype(ext));
  1548.            /*** Strip extension off of title***/
  1549.            filename[strlen(filename)-strlen(EXgetExt(ext))]= '\0';
  1550.            
  1551.            /**search for existing entry to add a view to **/
  1552.            num = GDSearch(gd, Pathp);
  1553.            if (num != -1) {
  1554.             if (GSgetType(GDgetEntry(gd,num)) == '\0') {
  1555.              GSsetHost(gs, NULL);
  1556.              GSmerge(GDgetEntry(gd, num), gs);
  1557.             }
  1558.             gs = GDgetEntry(gd, num);
  1559.             AddItem = FALSE;
  1560.            } 
  1561.            if (isGplus) {
  1562.             char *lang;
  1563.  
  1564.             lang = EXgetVLang(ext);
  1565.             if (lang == NULL || strcmp(lang, "")==0)
  1566.              lang = GDCgetLang(Config);
  1567.             GSaddView(gs, EXgetView(ext), lang, statbuf.st_size);
  1568.            }
  1569.       } 
  1570.       else if (AddItem) {
  1571.            int num;
  1572.            char type;
  1573.            char *path;
  1574.  
  1575.            num = GDSearch(gd, GSgetPath(gs));
  1576.            if (num != -1) {
  1577.             type = GSgetType(gs);
  1578.             path = GSgetPath(gs);
  1579.             gs = GDgetEntry(gd, num);
  1580.             GSsetType(gs, type);
  1581.             GSsetPath(gs, path);
  1582.             AddItem = FALSE;
  1583.            } 
  1584.            if (isGplus && GSisGplus(gs))
  1585.             AddDefaultView(gs, statbuf.st_size, NULL);
  1586.       }
  1587.  
  1588.       if (GSgetTitle(gs) == NULL) {
  1589.            /*** Check to see if we have a compressed file ***/
  1590.           /* Check moved to further up */ 
  1591.            
  1592.            GSsetTitle(gs, filename);
  1593.       }
  1594.       else
  1595.            GSsetTitle(gs, filename);
  1596.       
  1597.       GStitlefromDL(gs, filename); /** Check DL database for a good name **/
  1598. #ifdef CAPFILES
  1599.       if ((SideFile = rfopen(sidename, "r"))!=0) {
  1600.            if (DEBUG == TRUE)
  1601.             printf("Side file name: %s\n", sidename);
  1602.            Process_Side(SideFile, Gopherp);
  1603.            close (SideFile);
  1604.       }
  1605. #endif
  1606.       
  1607.       if (isGplus) {
  1608.            char tmpstr[256];
  1609.            char timeval[16];
  1610.            struct tm *tmthing;
  1611.            
  1612.            if (GSgplusInited(gs) == FALSE)
  1613.             GSplusnew(gs);
  1614.            
  1615.            /*** Add admin, abstract entries, etal ***/
  1616.            sprintf(tmpstr, "%s <%s>", 
  1617.                GDCgetAdmin(Config), GDCgetAdminEmail(Config));
  1618.            GSsetAdmin(gs, tmpstr);
  1619.            
  1620.            /** Set mod date entry **/
  1621.            tmthing = localtime(&(statbuf.st_mtime));
  1622.            strftime(timeval,sizeof(timeval), "%Y%m%d%H%M%S", tmthing);
  1623.            sprintf(tmpstr,"%s<%s>", asctime(tmthing),timeval);
  1624.            *(strchr(tmpstr, '\n')) = ' ';
  1625.            
  1626.            GSsetModDate(gs, tmpstr);
  1627.       }
  1628.       
  1629.       /*** Add the entry to the directory ***/
  1630.       if (AddItem) {
  1631.            GDaddGS(gd, gs);
  1632.       } else
  1633.            AddItem = TRUE;
  1634.       
  1635.       
  1636.      }
  1637.  
  1638.      for (i=0 ; i<STAgetTop(Linkfiles); i++) {
  1639.       int linkfd; 
  1640.  
  1641.       linkfd = uopen(STRget(STAgetEntry(Linkfiles,i)), O_RDONLY);
  1642.      
  1643.       if (linkfd >0) {
  1644.            GDfromLink(gd, linkfd, Zehostname, GopherPort, pathname);
  1645.            close(linkfd);
  1646.       }
  1647.      }
  1648.  
  1649.      closedir(ZeDir);
  1650.      
  1651.      GDsort(gd);
  1652.      
  1653.      return(gd);
  1654.      
  1655. }
  1656.  
  1657.  
  1658.  
  1659. GopherDirObj *
  1660. GDfromSelstr(selstr,sockfd)
  1661.   char *selstr;
  1662.   int sockfd;
  1663. {
  1664.      char directory[256];
  1665.      char *cp;
  1666.      GopherDirObj *gd;
  1667.  
  1668.      /** For now, strip off first character and find the directory above **/
  1669.      
  1670.      if (DEBUG) fprintf(stderr, "GDfromSelstr:*selstr=%c\r\n",*selstr);
  1671.      switch (*selstr) {
  1672.      case '0':
  1673.      case '1':
  1674.      case '7':
  1675.      case '9':
  1676.      case 's':
  1677.      case 'm':
  1678.      case 'I':
  1679.  
  1680.       strcpy(directory, selstr+1);
  1681.       break;
  1682.  
  1683.      case 'R':
  1684.       cp = strchr(selstr, '-');
  1685.       if (cp == NULL)  break;
  1686.  
  1687.       cp++;
  1688.       cp = strchr(cp, '-');
  1689.       if (cp == NULL) break;
  1690.       
  1691.       strcpy(directory, cp+1);
  1692.  
  1693.       break;
  1694.  
  1695.      default:
  1696.       if (DEBUG) fprintf(stderr,"GDfromSelstr:default\r\n");
  1697.       if (*selstr == '\0') {
  1698.            strcpy(directory, "//");
  1699.       } else {
  1700.            cp = strchr(selstr, ':');
  1701.            if (cp!=NULL) 
  1702.             strcpy(directory, cp+1);
  1703.            else
  1704.             strcpy(directory, selstr);
  1705.       }
  1706.      }
  1707.  
  1708.      cp = strrchr(directory, '/');
  1709.      if (cp != NULL)
  1710.       *(cp+1) = '\0';
  1711.      
  1712.      if (rchdir(directory)<0) {
  1713.       char tmpstr[512];
  1714.       sprintf(tmpstr, "- Cannot access directory '%s'", directory);
  1715.       Abortoutput(sockfd, tmpstr);
  1716.       return(NULL);
  1717.      }
  1718.      
  1719.      gd = GDfromUFS(directory, sockfd, TRUE); /** Returns NULL if error **/
  1720.      
  1721.      return(gd);
  1722. }
  1723.  
  1724.  
  1725. /*
  1726.  * Send item information to client
  1727.  */
  1728. item_info(selstr, sockfd)
  1729.   char *selstr;
  1730.   int sockfd;
  1731. {
  1732.      GopherDirObj *gd;
  1733.      GopherObj *gs;
  1734.      int num;
  1735.      char *cp;
  1736.      char tmpstr[256];
  1737.  
  1738.  
  1739.      gd = GDfromSelstr(selstr,sockfd);
  1740.      /** For now, strip off first character and find the directory above **/
  1741.      /* Note that GDfromSelstr will return NULL (i hope) if cant find dir */
  1742.  
  1743.      switch (*selstr) {
  1744.      case '0':
  1745.      case '1':
  1746.      case '7':
  1747.      case '9':
  1748.      case 's':
  1749.  
  1750.       num = GDSearch(gd, selstr);
  1751.       uchdir("/");
  1752.  
  1753.  
  1754.       if (num < 0)
  1755.            ; /*** Error message ***/
  1756.       else {
  1757.            gs = GDgetEntry(gd, num);
  1758.            GSsendHeader(sockfd, -2);
  1759.            GSplustoNet(gs, sockfd, NULL);
  1760.       }
  1761.       break;
  1762.  
  1763.      case '/':
  1764.      case '\0':
  1765.       gs = GSnew();
  1766.       GSsetHost(gs, Zehostname);
  1767.       GSsetPort(gs, GopherPort);
  1768.       GSsetPath(gs, "");
  1769.       GSsetTitle(gs, GDCgetSite(Config));
  1770.       GSsetType(gs, '1');
  1771.       GSsetGplus(gs, TRUE);
  1772.  
  1773.       GSsendHeader(sockfd, -2);
  1774.       writestring(sockfd, "+INFO ");
  1775.       GStoNet(gs,sockfd);
  1776.       sprintf(tmpstr, "+ADMIN\r\n Admin: %s <%s>\r\n", GDCgetAdmin(Config),
  1777.           GDCgetAdminEmail(Config));
  1778.       writestring(sockfd, tmpstr);
  1779.       sprintf(tmpstr, " Site: %s\r\n", GDCgetSite(Config));
  1780.       writestring(sockfd, tmpstr);
  1781.       sprintf(tmpstr, " Org: %s\r\n", GDCgetOrg(Config));
  1782.       writestring(sockfd, tmpstr);
  1783.       sprintf(tmpstr, " Loc: %s\r\n", GDCgetLoc(Config));
  1784.       writestring(sockfd, tmpstr);
  1785.       sprintf(tmpstr, " Geog: %s\r\n", GDCgetGeog(Config));
  1786.       writestring(sockfd, tmpstr);
  1787.  
  1788.       writestring(sockfd, "+VIEWS\r\n");
  1789.       writestring(sockfd, " Directory: <0k>\r\n");
  1790.       writestring(sockfd, " Directory+: <0k>\r\n");
  1791.       writestring(sockfd, " Directory/recursive: <0k>\r\n");
  1792.       writestring(sockfd, " Directory+/recursive: <0k>\r\n");
  1793.  
  1794.       break;
  1795.      }
  1796. }
  1797.      
  1798.  
  1799. /*
  1800. ** This function lists out what is in a particular directory.
  1801. ** it also outputs the contents of link files.
  1802. **
  1803. ** It also checks for the existance of a .cache file if caching is
  1804. ** turned on...
  1805. **
  1806. ** Ack is this ugly.
  1807. */
  1808.  
  1809. void
  1810. listdir(sockfd, pathname, isgplus, view, filter)
  1811.   int sockfd;
  1812.   char *pathname;
  1813.   boolean isgplus;
  1814.   char *view;
  1815.   char *filter;
  1816. {
  1817.      GopherDirObj *gd;
  1818.      boolean      attrlist = FALSE;
  1819.      boolean      Recurse  = FALSE;
  1820.      char         *filtereddata[16], **filtered=filtereddata;
  1821.      int          i=0;
  1822.      StrArray     *RecurseDirs;
  1823.      String       *stapath;
  1824.      String       *pushstring = STRnew();
  1825.  
  1826.      if (uchdir("/"))
  1827.       perror("SOL dude");
  1828.  
  1829.      if (filter != NULL) {
  1830.       while (*filter != '\0') {
  1831.            if (*filter=='+') {
  1832.             *filter = '\0';
  1833.             filtered[i] = filter+1;
  1834.             filter++; i++;
  1835.            }
  1836.            filter++;
  1837.       }
  1838.       filtered[i] = NULL;
  1839.      } else
  1840.       filtered = NULL;
  1841.  
  1842.  
  1843.      if (view != NULL) {
  1844.       if (strncmp(view, "Directory+",10) == 0)
  1845.            attrlist = TRUE;
  1846.       if (strncmp(view, "Directory+/recursive", 20)==0)
  1847.            Recurse = TRUE;
  1848.       if (strncmp(view, "Directory/recursive", 19)==0)
  1849.            Recurse = TRUE;
  1850.      }
  1851.      if (Recurse)
  1852.       RecurseDirs = STAnew(32);
  1853.  
  1854.      if (Can_Browse(sockfd) == FALSE) {
  1855.       char tmpstr[256];
  1856.       Abortoutput(sockfd,  GDCgetBummerMsg(Config));
  1857.       sprintf(tmpstr, "Denied access for %s", pathname);
  1858.       LOGGopher(sockfd, tmpstr);
  1859.       return;
  1860.      }
  1861.  
  1862.  
  1863.      if (DEBUG) fprintf(stderr,"listdir: pathname=%s, isgplus=%d, view=%s\r\n",
  1864.             pathname, isgplus, view);
  1865.      if (rchdir(pathname)<0) {
  1866.       if (errno == EACCES)
  1867. #ifdef UMNDES
  1868.            PleaseAuthenticate(sockfd);
  1869. #endif
  1870.       ;
  1871.       Abortoutput(sockfd, "- Cannot access that directory");
  1872.       return;
  1873.      }
  1874.  
  1875.      if (isgplus)
  1876.       GSsendHeader(sockfd, -1);
  1877.  
  1878.  
  1879.      do {
  1880.       if (DEBUG)
  1881.            printf("Sending %s\n", pathname);
  1882.  
  1883.       if (Recurse) {
  1884.            rchdir("/");
  1885.            if (rchdir(pathname)<0) {
  1886.             continue;
  1887.            }
  1888.       }
  1889.  
  1890.  
  1891.  
  1892.       if (Caching) {
  1893.  
  1894.            if (!attrlist && Cachetimedout(".cache", CACHE_TIME, ".")==FALSE) {
  1895.             /*** Old style cache  ***/
  1896.             printfile(sockfd, ".cache", 0, -1, FALSE);
  1897.             return;
  1898.            } else if (Cachetimedout(".cache+", CACHE_TIME, ".")==FALSE) {
  1899.             /*** Gopher+ cache. ***/
  1900.             
  1901.             if (strcmp(view, "Directory+")==0) {
  1902.              printfile(sockfd, ".cache+", 0, -1, FALSE);
  1903.              return;
  1904.             } else if (strcmp(view, "Directory")==0) {
  1905.              printfile(sockfd, ".cache", 0, -1, FALSE);
  1906.              return;
  1907.             }
  1908.            }
  1909.       }
  1910.  
  1911.       /** If we didn't cache then we have to load up the directory **/
  1912.       gd = GDfromUFS(pathname, sockfd, attrlist);
  1913.  
  1914.       if (gd == NULL) {
  1915.            /** Should generate an error message here **/
  1916.            return;
  1917.       }
  1918.       
  1919.       rchdir("/");
  1920.       
  1921.       if (attrlist)
  1922.            GDplustoNet(gd, sockfd,filtered);
  1923.       else
  1924.            GDtoNet(gd, sockfd);
  1925.  
  1926.  
  1927.       /*
  1928.        * Write out the cache... *After* we send out the data to the net.
  1929.        */
  1930.       if (Caching) {
  1931.            int cachefd;
  1932.            char cachefile[MAXPATHLEN], *cp;
  1933.            
  1934.            strcpy(cachefile, pathname);
  1935.            strcat(cachefile, "/.cache");
  1936.            
  1937.            cachefd = ropen(cachefile, O_WRONLY|O_CREAT|O_TRUNC, 0644);
  1938.            
  1939.            if (cachefd != 0) {
  1940.             if (DEBUG) {
  1941.              printf("Caching directory... into %s\n",cachefile);
  1942.             }
  1943.             GDtoNet(gd, cachefd);
  1944.             close(cachefd);
  1945.            }
  1946.            
  1947.            if (attrlist) {
  1948.             strcat(cachefile, "+");
  1949.             
  1950.             cachefd = ropen(cachefile, O_WRONLY|O_CREAT|O_TRUNC,0644);
  1951.             
  1952.             if (cachefd) {
  1953.              GDplustoNet(gd, cachefd,filtered);
  1954.              close(cachefd);
  1955.             }
  1956.            }
  1957.       }
  1958.  
  1959.       
  1960.       if (Recurse) {
  1961.            GopherObj *gs;
  1962.            /** Push entries on the stack **/
  1963.            for (i=0; i< GDgetNumitems(gd); i++) {
  1964.             gs = GDgetEntry(gd, i);
  1965.             if ((GSgetType(gs) == A_DIRECTORY) &&
  1966.             (strcmp(GSgetHost(gs), Zehostname) == 0)) {
  1967.              STRset(pushstring,  GSgetPath(gs));
  1968.              STApush(RecurseDirs, pushstring);
  1969.             }
  1970.            }
  1971.  
  1972.            do {
  1973.             stapath = STApop(RecurseDirs);
  1974.             if (stapath == NULL) {
  1975.              Recurse = FALSE;  /** Done **/
  1976.              break;
  1977.             }
  1978.             pathname = STRget(stapath);
  1979.             
  1980.             if (*pathname == 'm')
  1981.              process_mailfile(sockfd, pathname+1);
  1982.            } while (*pathname == 'm');
  1983.  
  1984.            pathname++;
  1985.  
  1986.       }
  1987.  
  1988.      } while (Recurse);
  1989.  
  1990.      writestring(sockfd, ".\r\n");
  1991.  
  1992. }
  1993.  
  1994.  
  1995. /*
  1996.  * This processes a file containing any subset of
  1997.  * Type, Name, Path, Port or Host, and returns pointers to the
  1998.  * overriding data that it finds.
  1999.  *
  2000.  * The caller may choose to initialise the pointers - so we don't
  2001.  * touch them unless we find an over-ride.
  2002.  */
  2003.  
  2004. void
  2005. Process_Side(sidefile, Gopherp)
  2006.   FILE *sidefile;
  2007.   GopherObj *Gopherp;
  2008. {
  2009.      char inputline[MAXLINE];
  2010.      char *cp;
  2011.  
  2012.  
  2013.      inputline[0] = '\0';
  2014.  
  2015.      for (;;) {
  2016.       for (;;) {
  2017.            cp = fgets(inputline, 1024, sidefile);
  2018.            if (inputline[0] != '#' || cp == NULL)
  2019.             break;
  2020.       }
  2021.       
  2022.       /*** Test for EOF ***/
  2023.       if (cp==NULL)
  2024.            break;
  2025.       
  2026.       ZapCRLF(inputline);  /* should zap tabs as well! */
  2027.  
  2028.       /*** Test for the various field values. **/
  2029.       
  2030.       if (strncmp(inputline, "Type=", 5)==0) {
  2031.            GSsetType(Gopherp, inputline[5]);
  2032.            if (inputline[5] == '7') {
  2033.             /*** Might as well set the path too... ***/
  2034.             *(GSgetPath(Gopherp)) = '7';
  2035.            }
  2036.            if (inputline[5] == '9') {
  2037.             /*** Might as well set the path too... ***/
  2038.             *(GSgetPath(Gopherp)) = '9';
  2039.            }
  2040.       }
  2041.  
  2042.       else if (strncmp(inputline, "Name=", 5)==0) {
  2043.            GSsetTitle(Gopherp, inputline+5);
  2044.       }
  2045.  
  2046.       else if (strncmp(inputline, "Host=", 5)==0) {
  2047.            GSsetHost(Gopherp, inputline+5);
  2048.       }
  2049.  
  2050.       else if (strncmp(inputline, "Port=", 5)==0) {
  2051.            GSsetPort(Gopherp, atoi(inputline+5));
  2052.       }
  2053.  
  2054.       else if (strncmp(inputline, "Path=", 5)==0) {
  2055.            GSsetPath(Gopherp, inputline+5);
  2056.       }
  2057.  
  2058.       else if (strncmp(inputline, "Numb=", 5)==0) {
  2059.            GSsetNum(Gopherp, atoi(inputline+5));
  2060.       }
  2061.  
  2062.       else if (strncmp(inputline, "Name=", 5)==0) {
  2063.            GSsetTitle(Gopherp, inputline+5);
  2064.       }
  2065.  
  2066.       else if (strncmp(inputline, "Abstract=", 9)==0) {
  2067.            GSsetAbstract(Gopherp, inputline+9);
  2068.       }
  2069.  
  2070.      }
  2071.  
  2072.      fclose(sidefile);
  2073. }
  2074.  
  2075.  
  2076.  
  2077.  
  2078.  
  2079. /*
  2080. ** This function opens the specified file, starts a zcat if needed,
  2081. ** and barfs the file across the socket.
  2082. **
  2083. ** It now also checks and sees if access is allowed
  2084. **
  2085. */
  2086.  
  2087. void
  2088. printfile(sockfd, pathname, startbyte, endbyte, Gplus)
  2089.   int     sockfd;
  2090.   char    *pathname;
  2091.   int     startbyte, endbyte;
  2092.   boolean Gplus;
  2093. {
  2094.      FILE *ZeFile;
  2095.      char inputline[512];
  2096.      FILE *pp;
  2097.  
  2098.  
  2099.      /*** Check and see if the peer has permissions to read files ***/
  2100.      
  2101.      if (Can_Read(sockfd) == FALSE) {
  2102.       char tmpstr[256];
  2103.       if (writestring(sockfd, GDCgetBummerMsg(Config)) <0)
  2104.            LOGGopher(sockfd, "Client went away"), exit(-1);
  2105.       writestring(sockfd, "\r\nBummer.....\r\n.\r\n");
  2106.       sprintf(tmpstr, "Denied access for %s", pathname);
  2107.       LOGGopher(sockfd, tmpstr);
  2108.       return;
  2109.      }
  2110.  
  2111.  
  2112.      /* Try opening pathname and pathname.Z (or take off .Z if already on) */
  2113.  
  2114.      if ( (ZeFile = rfopenz(pathname, "r")) == NULL) {
  2115.       /*
  2116.        * The specified file does not exist
  2117.        */
  2118.       char notexistline[256];
  2119.       sprintf(notexistline, "'%s' does not exist!!", pathname);
  2120.       Abortoutput(sockfd, notexistline);
  2121.  
  2122.       return;
  2123.      }
  2124.  
  2125.      if (startbyte != 0)
  2126.       fseek(ZeFile, startbyte, 0);
  2127.      
  2128.      if (pp = specialfile(ZeFile, pathname)) {
  2129.       fclose(ZeFile);
  2130.       ZeFile = pp;
  2131.      }
  2132.  
  2133.      if (Gplus)
  2134.       GSsendHeader(sockfd, -1);
  2135.  
  2136.      while (fgets(inputline, sizeof(inputline), ZeFile) != NULL) {
  2137.  
  2138.       ZapCRLF(inputline);
  2139.  
  2140.       /** Period on a line by itself, double it.. **/
  2141.       if (*inputline == '.' && inputline[1] == '\0') {
  2142.            inputline[1] = '.';
  2143.            inputline[2] = '\0';
  2144.       }
  2145.  
  2146.       strcat(inputline, "\r\n");
  2147.       if (writestring(sockfd, inputline) <0)
  2148.            LOGGopher(sockfd, "Client went away"), exit(-1);
  2149.  
  2150.       if (endbyte >0) {
  2151.            if (ftell(ZeFile) >= endbyte)
  2152.             break;
  2153.       }
  2154.      }
  2155.  
  2156.      Specialclose(ZeFile);
  2157.  
  2158.      if (writestring(sockfd, ".\r\n")<0)
  2159.       LOGGopher(sockfd, "Client went away"), exit(-1);
  2160. }
  2161.  
  2162.  
  2163. #define BUFSIZE 1523  /* A pretty good value for ethernet */
  2164.  
  2165. void
  2166. echosound(sockfd, filename, isGplus)
  2167.   int sockfd;
  2168.   char *filename;
  2169.   boolean isGplus;
  2170. {
  2171.  
  2172.      FILE *sndfile;
  2173.      unsigned char in[BUFSIZE];
  2174.      register int j;
  2175.      int gotbytes, size;
  2176.      struct stat buf;
  2177.  
  2178.      if (Can_Read(sockfd) == FALSE) {
  2179.       char tmpstr[256];
  2180.       if (writestring(sockfd, GDCgetBummerMsg(Config)) <0)
  2181.            LOGGopher(sockfd, "Client went away"), exit(-1);
  2182.       writestring(sockfd, "\r\nBummer.....\r\n.\r\n");
  2183.       sprintf(tmpstr, "Denied access for %s", filename);
  2184.       LOGGopher(sockfd, tmpstr);
  2185.       return;
  2186.      }
  2187.  
  2188.  
  2189.      if (strcmp(filename, "-") == 0) {
  2190.       /*** Do some live digitization!! **/
  2191.       sndfile = popen("record -", "r");
  2192.      }
  2193.      else
  2194.       sndfile = rfopen(filename, "r");
  2195.  
  2196.      if ((isGplus) && strcmp(filename, "-") == 0) 
  2197.       GSsendHeader(sockfd, -2);
  2198.      else if (isGplus) {
  2199.       rstat(filename, &buf);
  2200.       size = buf.st_size;
  2201.       GSsendHeader(sockfd, size);
  2202.      }
  2203.  
  2204.  
  2205.      while(1) {
  2206.       gotbytes = fread(in, 1, BUFSIZE, sndfile);
  2207.       
  2208.       if (gotbytes == 0)
  2209.            break;       /*** end of file or error... ***/
  2210.  
  2211.           j = writen(sockfd, in, gotbytes);
  2212.  
  2213.       if (j == 0)
  2214.            break;       /*** yep another error condition ***/
  2215.  
  2216.      }
  2217. }
  2218.  
  2219.